/**
 * <p>文件名:		XXX.java</p>
 * <p>版权:		CopyrightTag</p>
 * <p>公司:		CompanyTag</p>
 * @author		周华彬(zhouhuabin@chinatransinfo.com, zhou_hua_bin@163.com)
 */

package com.caits.lbs.framework.utils;

import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.slf4j.Logger;

import com.caits.lbs.framework.log.CommonSlf4jLogFactory;

/**
 * <p>
 * Cryptos常见加密类，HMac,AES工具类。
 * 高级加密标准（英语：Advanced Encryption Standard，缩写：AES），在密码学中又称Rijndael加密法，是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES，
 * AES的区块长度固定为128 比特，密钥长度则可以是128，192或256比特.
 * 几种对称性加密算法：AES,DES,3DES;
 * 几种非对称性加密算法：RSA,DSA,ECC;
 * 几种线性散列算法（签名算法）：MD5,SHA1,HMAC;
 * 一般来说，RSA建议采用1024位的数字，ECC建议采用160位，AES采用128为即可.
 * </p>
 * <p>
 * 对称加密算法的密钥管理是一个复杂的过程，密钥的管理直接决定着他的安全性，当数据量很小时，可以考虑采用非对称加密算法。
通常采用的方式是：采用非对称加密算法管理对称算法的密钥，然后用对称加密算法加密数据，这样我们就集成了两类加密算法的优点，既实现了加密速度快的优点，又实现了安全方便管理密钥的优点
 * </p>
 * @author 周华彬(zhouhuabin@chinatransinfo.com, zhou_hua_bin@163.com)
 * @version 0.0.0
 *          <table style="border:1px solid gray;">
 *          <tr>
 *          <th width="100px">版本号</th>
 *          <th width="100px">动作</th>
 *          <th width="100px">修改人</th>
 *          <th width="100px">修改时间</th>
 *          </tr>
 *          <!-- 以 Table 方式书写修改历史 -->
 *          <tr>
 *          <td>0.0.0</td>
 *          <td>创建类</td>
 *          <td>zhouhuabin</td>
 *          <td>2015年9月15日 上午10:37:54</td>
 *          </tr>
 *          <tr>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          </tr>
 *          </table>
 */

public class Cryptos {
	protected static Logger log = CommonSlf4jLogFactory.getLog();
	private static final String AES = "AES";
	private static final String AES_CBC = "AES/CBC/PKCS5Padding";
	private static final String HMACSHA1 = "HmacSHA1";
	private static final int DEFAULT_HMACSHA1_KEYSIZE = 160;
	private static final int DEFAULT_AES_KEYSIZE = 128;
	private static final int DEFAULT_IVSIZE = 16;
	/** 变量:此类提供加密的强随机数生成器 (RNG),类型:SecureRandom */
	private static SecureRandom random = new SecureRandom();

	public static byte[] hmacSha1(byte[] input, byte[] key) {
		try {
			SecretKey secretKey = new SecretKeySpec(key, HMACSHA1);
			Mac mac = Mac.getInstance(HMACSHA1);
			mac.init(secretKey);
			return mac.doFinal(input);
		} catch (GeneralSecurityException e) {
			log.error("Security error.",e);
		}
		return new byte[0];
	}

	public static boolean isMacValid(byte[] expected, byte[] input, byte[] key) {
		byte[] actual = hmacSha1(input, key);
		return Arrays.equals(expected, actual);
	}

	public static byte[] generateHmacSha1Key() {
		try {
			KeyGenerator keyGenerator = KeyGenerator.getInstance(HMACSHA1);
			keyGenerator.init(DEFAULT_HMACSHA1_KEYSIZE);
			SecretKey secretKey = keyGenerator.generateKey();
			return secretKey.getEncoded();
		} catch (GeneralSecurityException e) {
			log.error("Security error.",e);
		}
		return new byte[0];
	}

	public static byte[] aesEncrypt(byte[] input, byte[] key) {
		return aes(input, key, 1);
	}

	public static byte[] aesEncrypt(byte[] input, byte[] key, byte[] iv) {
		return aes(input, key, iv, 1);
	}

	public static String aesDecrypt(byte[] input, byte[] key) {
		byte[] decryptResult = aes(input, key, 2);
		return new String(decryptResult);
	}

	public static String aesDecrypt(byte[] input, byte[] key, byte[] iv) {
		byte[] decryptResult = aes(input, key, iv, 2);
		return new String(decryptResult);
	}

	private static byte[] aes(byte[] input, byte[] key, int mode) {
		try {
			SecretKey secretKey = new SecretKeySpec(key, AES);
			Cipher cipher = Cipher.getInstance(AES);
			cipher.init(mode, secretKey);
			return cipher.doFinal(input);
		} catch (GeneralSecurityException e) {
			log.error("Security error.",e);
		}
		return new byte[0];
	}

	private static byte[] aes(byte[] input, byte[] key, byte[] iv, int mode) {
		try {
			SecretKey secretKey = new SecretKeySpec(key, AES);
			IvParameterSpec ivSpec = new IvParameterSpec(iv);
			Cipher cipher = Cipher.getInstance(AES_CBC);
			cipher.init(mode, secretKey, ivSpec);
			return cipher.doFinal(input);
		} catch (GeneralSecurityException e) {
			log.error("Security error.",e);
		}
		return new byte[0];
	}

	public static byte[] generateAesKey() {
		return generateAesKey(DEFAULT_AES_KEYSIZE);
	}

	/**
	 * 种子生成器 
	 * @param keysize
	 * @return byte[]
	 */
	public static byte[] generateAesKey(int keysize) {
		try {
			KeyGenerator keyGenerator = KeyGenerator.getInstance(AES);
			keyGenerator.init(keysize);
			SecretKey secretKey = keyGenerator.generateKey();
			return secretKey.getEncoded();
		} catch (GeneralSecurityException e) {
			log.error("Security error.",e);
		}
		return new byte[0];
	}

	/**
	 * 生成强随机字节 
	 * @return byte[]
	 */
	public static byte[] generateIV() {
		byte[] bytes = new byte[DEFAULT_IVSIZE];
		random.nextBytes(bytes);
//		random.setSeed(seed);
		return bytes;
	}
}
